﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Linq.Dynamic;
using System.Web;
using System.Web.DynamicData;
using System.Web.UI;
using System.Web.UI.WebControls;
using Data.LINQ;

namespace Dimok.Web.UI {
	public class RenderTable<TContext> where TContext:DataContext {

		#region Members
		MetaModel metaModel;
		DataContext context;
		string id;
		Type entityType;
		BoundField[] columns;
		string[] orderBys;
		Dictionary<string, object> key;
		string[] dataKeyNames;
		#endregion

		#region Constructors
		public RenderTable(string ID, Type EntityType, BoundField[] Columns, string[] OrderBys, object Key) :
			this(ID, EntityType, Columns, OrderBys, Key.ToDictionary()) {
		}
		public RenderTable(string ID, Type EntityType, BoundField[] Columns, string[] OrderBys, Dictionary<string, object> Key)
			: this() {
			Init(ID, EntityType, Columns, OrderBys, Key);
		}
		public RenderTable(string ID, string EntityType, BoundField[] Columns, string[] OrderBys, Dictionary<string, object> Key)
			: this() {
			Init(ID, metaModel.GetEntityType(EntityType,true), Columns, OrderBys, Key);
		}
		public RenderTable() {
			this.context = Activator.CreateInstance<TContext>();
			this.metaModel = MetaModel.GetModel(typeof(TContext));
		}
		protected void Init(string ID, Type EntityType, BoundField[] Columns, string[] OrderBys, Dictionary<string, object> Key) {
			this.id = ID; this.entityType = EntityType; this.columns = Columns; this.orderBys = OrderBys; this.key = Key;
			dataKeyNames = Columns.Where(c => !c.Visible).Select(c => c.DataField)
				.Union(metaModel.GetClientKeyNames(entityType)).ToArray();
			foreach (var bf in columns) {
				if (bf.HeaderText == "") bf.HeaderText = bf.DataField.MakeHeader();
				if (bf.DataFormatString == "" && metaModel.GetMetaColumn(entityType, bf.DataField, true).ColumnType == typeof(DateTime))
					bf.DataFormatString = "{0:MM/dd/yyyy}";
			}
		}
		#endregion

		#region Render
		internal string Render() {
			var grv = new GridView() { ID = id, DataKeyNames = dataKeyNames, AutoGenerateColumns = false/*,Caption="X",CaptionAlign= TableCaptionAlign.Right*/ };
			foreach (var column in columns)
				grv.Columns.Add(column);
			LinqDataSource linqDS = new LinqDataSource();
			linqDS.Selecting += new EventHandler<LinqDataSourceSelectEventArgs>(linqDS_Selecting);
			grv.RowCreated += new GridViewRowEventHandler(grv_RowCreated);
			grv.DataSource = linqDS;
			grv.DataBind();
			System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(new System.IO.StringWriter());
			grv.RenderControl(htmlWrite);
			return htmlWrite.InnerWriter.ToString();
		}

		void grv_RowCreated(object sender, GridViewRowEventArgs e) {
			if (e.Row.RowType != DataControlRowType.DataRow) return;
			foreach (string dataKey in dataKeyNames)
				e.Row.Attributes.Add(dataKey, e.Row.DataItem.GetProperty(dataKey) + "");
		}
		void linqDS_Selecting(object sender, LinqDataSourceSelectEventArgs e) {
			string filter = string.Join(" && ", key.Select((k, i) => k.Key + "=@" + i).ToArray());
			var r = context.GetTable(entityType).Where(filter, key.Values.ToArray());
			var select = from bf in columns.Select(c => c.DataField).Union(dataKeyNames)
									 join mc in metaModel.GetTable(entityType).Columns.Select(c => c.Name)
									 on bf equals mc
									 select bf;
			r = r.Select("new (" + string.Join(",", select.ToArray()) + ")");
			if (orderBys != null && orderBys.Length > 0) r = r.OrderBy(string.Join(",", orderBys));
			e.Result = r;
		}
		#endregion

		#region Static Render
		public static string Render(string ID, string EntityType, BoundField[] Columns, string[] OrderBys, object Key) {
			return Render(ID, EntityType, Columns, OrderBys, Key.ToDictionary());
		}
		public static string Render(string ID, string EntityType, BoundField[] Columns, string[] OrderBys,Dictionary<string, object> Key) {
			var rt = new RenderTable<TContext>(ID, EntityType, Columns, OrderBys, Key);
			return rt.Render();
		}
		public static string Render(string ID, Type EntityType, BoundField[] Columns, string[] OrderBys, object Key) {
			return Render(ID, EntityType, Columns, OrderBys, Key.ToDictionary());
		}
		public static string Render(string ID, Type EntityType, BoundField[] Columns, string[] OrderBys, Dictionary<string, object> Key) {
			var rt = new RenderTable<TContext>(ID, EntityType, Columns, OrderBys, Key);
			return rt.Render();
		}
		#endregion

	}
}